#include "lib/print.h"
#include "dev/timer.h"
#include "dev/uart.h"
#include "dev/plic.h"
#include "trap/trap.h"
#include "proc/cpu.h"
#include "memlayout.h"
#include "riscv.h"
#include "dev/vio.h"
// 中断信息
char* interrupt_info[16] = {
    "U-mode software interrupt",      // 0
    "S-mode software interrupt",      // 1
    "reserved-1",                     // 2
    "M-mode software interrupt",      // 3
    "U-mode timer interrupt",         // 4
    "S-mode timer interrupt",         // 5
    "reserved-2",                     // 6
    "M-mode timer interrupt",         // 7
    "U-mode external interrupt",      // 8
    "S-mode external interrupt",      // 9
    "reserved-3",                     // 10
    "M-mode external interrupt",      // 11
    "reserved-4",                     // 12
    "reserved-5",                     // 13
    "reserved-6",                     // 14
    "reserved-7",                     // 15
};

// 异常信息
char* exception_info[16] = {
    "Instruction address misaligned", // 0
    "Instruction access fault",       // 1
    "Illegal instruction",            // 2
    "Breakpoint",                     // 3
    "Load address misaligned",        // 4
    "Load access fault",              // 5
    "Store/AMO address misaligned",   // 6
    "Store/AMO access fault",         // 7
    "Environment call from U-mode",   // 8
    "Environment call from S-mode",   // 9
    "reserved-1",                     // 10
    "Environment call from M-mode",   // 11
    "Instruction page fault",         // 12
    "Load page fault",                // 13
    "reserved-2",                     // 14
    "Store/AMO page fault",           // 15
};

// in trap.S
// 内核中断处理流程
extern void kernel_vector();

// 初始化trap中全局共享的东西
void trap_kernel_init()
{
    plic_init();
    timer_create();
}

// 各个核心trap初始化
void trap_kernel_inithart()
{
    plic_inithart();
    w_stvec((uint64)kernel_vector);// 设置当前 hart 的陷入处理程序的入口地址为 kernel_vector
    intr_on();//打开中断
}

// 外设中断处理 (基于PLIC)
void external_interrupt_handler()
{ 
    int irq = plic_claim();  // 获取中断号
    // 如果没有有效的中断请求，直接返回
    if (irq == 0) {
        return; // 直接忽略中断
    }
    if (irq == UART_IRQ) {
        uart_intr();           // 处理 UART 中断
    }
    else if (irq == VIRTIO_IRQ){
        virtio_disk_intr();//处理virtio中断
    }
    else if (irq != 0) {
        printf("unexpected interrupt irq=%d\n", irq); // 处理未知中断
    }
    // 完成中断处理
    plic_complete(irq);
        
}

// 时钟中断处理 (基于CLINT)
void timer_interrupt_handler()
{
    // 仅在 CPU 0 上更新时钟
    if (mycpuid() == 0) {
        timer_update();  // 更新 ticks
    } 
    // 清除中断标志位
    w_sip(r_sip() & ~2); // 确认软件中断已处理
    
    if(myproc() != 0 && myproc()->state == RUNNING)
        proc_yield();

}

// 在kernel_vector()里面调用
// 内核态trap处理的核心逻辑
void trap_kernel_handler()
{
    uint64 sepc = r_sepc();          // 记录了发生异常时的pc值
    uint64 sstatus = r_sstatus();    // 与特权模式和中断相关的状态信息
    uint64 scause = r_scause();      // 引发trap的原因
    uint64 stval = r_stval();        // 发生trap时保存的附加信息(不同trap不一样)

    // 确认trap来自S-mode且此时trap处于关闭状态
    assert(sstatus & SSTATUS_SPP, "trap_kernel_handler: not from s-mode");
    assert(intr_get() == 0, "trap_kernel_handler: interreput enabled");

    int trap_id = scause & 0xf; 

    // 中断异常处理核心逻辑
    switch (trap_id) 
    {
        case 1: // S-mode software interrupt
            timer_interrupt_handler();
            break;
        case 5: // S-mode timer interrupt
            timer_interrupt_handler();
            break;
        case 9: // S-mode external interrupt
            external_interrupt_handler();
            break;
        // 添加其他中断和异常的处理
        default:
            if (scause & (1L << 63)) 
            {
            // 中断
                if (trap_id < 16) {
                    printf("Interrupt: %s\n", interrupt_info[trap_id]);
                    printf("trap occurred at sepc=%p, stval=%p\n", sepc, stval);
                    panic("trap_kernel_handler");
                } else {
                    printf("Unexpected interrupt: trap_id=%d\n", trap_id);
                    printf("trap occurred at sepc=%p, stval=%p\n", sepc, stval);
                    panic("trap_kernel_handler");
                }
            } 
            else {
                // 异常
                if (trap_id < 16) {
                    printf("Exception: %s\n", exception_info[trap_id]);
                    printf("trap occurred at sepc=%p, stval=%p\n", sepc, stval);
                    panic("trap_kernel_handler");
                } else {
                    printf("Unexpected exception: trap_id=%d\n", trap_id);
                    printf("trap occurred at sepc=%p, stval=%p\n", sepc, stval);
                    panic("trap_kernel_handler");
                }
            }
            break;
    }
    //回到sepc里记录的用户态进程去
    w_sepc(sepc);
    w_sstatus(sstatus);
}